﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace OmixJsonServer.Helpers
{
    public static class ReflectionHelper
    {
        public static bool AttributeExists(PropertyInfo pi, Type attributeType)
        {
            Attribute Attr = pi.GetCustomAttribute(attributeType);

            return (Attr != null);
            
        }

        public static bool AttributeExists(object obj, Type attributeType)
        {
            Attribute Attr = null;

            Attr = obj.GetType().GetCustomAttribute(attributeType);

            return (Attr != null);

        }

        public static bool PropertyExists<T>(T obj, string PropertyName) where T : class
        {
            return PropertyExists<T>(obj, PropertyName, false);
        }

        public static bool PropertyExists<T>(T obj, string PropertyName, bool CaseSensitive) where T : class
        {
            var bf = CaseSensitive ? (BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) :
                (BindingFlags.GetProperty | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

            return typeof(T).GetProperty(PropertyName, bf) != null;
        }

        public static object GetPropertyValue<T>(T obj, string PropertyName, bool CaseSensitive) where T : class
        {
            object Retval = null;

            var bf = CaseSensitive ? (BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) :
                  (BindingFlags.GetProperty | BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
            try
            {
                if (obj == null) return null;
                Retval = obj.GetType().GetProperty(PropertyName, bf).GetValue(obj, null);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return Retval;
        }

        public static object GetPropertyValue<T>(T obj, string propName) where T : class
        {
            return GetPropertyValue(obj, propName, false);
        }

        public static T SetPropertyValue<T>(T obj, string propName, object value) where T : class
        {
            try
            {
                PropertyInfo pi = obj.GetType().GetProperties().Where(p => string.Equals(propName, p.Name, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
                if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    pi.SetValue(obj, Convert.ChangeType(value, Nullable.GetUnderlyingType(pi.PropertyType)));
                }
                else
                {
                    if (value == null)
                    {
                        pi.SetValue(obj,null);
                    }
                    else
                    {
                        pi.SetValue(obj, Convert.ChangeType(value, pi.PropertyType));
                    }
                }
                
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return obj;
        }

        public static PropertyInfo GetProperty<T>(T obj, string PropertyName) where T : class
        {
            return GetProperties(obj).Where(p => string.Equals(PropertyName, p.Name)).FirstOrDefault();
        }

        public static PropertyInfo[] GetProperties(object obj)
        {
            return obj.GetType().GetProperties();
        }

        public static bool IsPropertyACollection(PropertyInfo property)
        {
            if (property.PropertyType.FullName == "System.String") return false;
            return property.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) != null;
        }

        public static bool IsPropertyAClass(PropertyInfo property)
        {
            if (property.PropertyType.FullName == "System.String") return false;
            return property.PropertyType.IsClass;
        }
    }
}
